TITLE 08-08-83 BIOS2  BIOS INTERRUPT
.XLIST
INCLUDE DSEG.SRC
INCLUDE POSTEQU.SRC
.LIST
INCLUDE SEGMENT.SRC
EXTRN	DDS:NEAR
PUBLIC	TIME_OF_DAY_1,TIMER_INT_1,PRINT_SCREEN_1
PUBLIC	RTC_INT
;--- INT 1A -----------------------------------------------------
; TIME_OF_DAY							:
;	THIS ROUTINE ALLOWS THE CLOCKS TO BE SET/READ		:
;								:
; INPUT:							:
;   (AH) = 0	READ THE CURRENT CLOCK SETTING			:
;		RETURNS CX = HIGH PORTION OF COUNT		:
;			DX = LOW PORTION OF COUNT		:
;			AL = 0 IF TIMER HAS NOT PASSED 24 HOURS :
;			SINCE LAST READ. <> 0 IF ON ANOTHER DAY :
;   (AH) = 1	SET THE CURRENT CLOCK				:
;	CX = HIGH PORTION OF COUNT				:
;	DX = LOW PORTION OF COUNT				:
;								:
; NOTE: COUNTS OCCUR AT THE RATE OF 1193180/65536 COUNTS/SEC	:
;	(OR ABOUT 18.2 PER SECOND -- SEE EQUATES)		:
;								:
;   (AH) = 2	READ THE REAL TIME CLOCK			:
;		RETURNS CH = HOURS IN BCD			:
;			CL = MINUTES IN BCD			:
;			DH = SECONDS IN BCD			:
;								:
;   (AH) = 3	SET THE REAL TIME CLOCK 			:
;	CH = HOURS IN BCD					:
;	CL = MINUTES IN BCD					:
;	DH = SECONDS IN BCD					:
;	DL = 1 IF DAYLIGHT SAVINGS ENABLE OPTION, ELSE 0	:
;								:
;   (AH) = 4	READ THE DATE FROM THE REAL TIME CLOCK		:
;		RETURNS CH = CENTURY IN BCD			:
;			CL = YEAR IN BCD			:
;			DH = MONTH IN BCD			:
;			DL = DAY IN BCD 			:
;								:
;   (AH) = 5	SET THE DATE INTO THE REAL TIME CLOCK		:
;	CH = CENTURY IN BCD					:
;	CL = YEAR IN BCD					:
;	DH = MONTH IN BCD					:
;	DL = DAY IN BCD 					:
;								:
;   (AH) = 6	SET THE ALARM					:
;		THE ALARM CAN BE SET TO INTERRUPT UP TO 	:
;		23:59:59 FROM PRESENT TIME.			:
;		ONE ALARM FUNCTION MAY BE ACTIVE AT ANY TIME	:
;								:
;	CH = HOURS IN BCD					:
;	CL = MINUTES IN BCD					:
;	DH = SECONDS IN BCD					:
;								:
;   (AH) = 7	RESET THE ALARM 				:
;								:
; NOTE: FOR AH = 2, 4, 6 - CY FLAG SET IF CLOCK NOT OPERATING	:
;	FOR AH = 6 - CY FLAG SET IF ALARM ALREADY ENABLED	:
; NOTE: FOR THE ALARM FUNCTION (AH = 6) THE USER MUST CODE A	:
;	ROUTINE AND PLACE THE CORRECT ADDRESS IN THE VECTOR	:
;	TABLE FOR INT 4AH					:
;----------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA

TIME_OF_DAY_1	PROC  FAR
	STI				; INTERRUPTS BACK ON
	PUSH	DS			; SAVE SEGMENT
	CALL	DDS			; SET DATA SEGMENT
	OR	AH,AH			; AH=0
	JZ	T2			; READ TIME
	DEC	AH			; AH=1
	JZ	T3			; SET TIME
	CMP	AH,7			; CHECK IF VALID
	JGE	T1			; RETURN IF NOT VALID
	JMP	RTC_0			; GO CHECK OTHER FUNCTIONS
T1:
	STI				; INTERRUPTS BACK ON
	POP	DS			; RECOVER SEGMENT
	IRET				; RETURN TO CALLER
T1_A:
	STC				; SET ERROR RETURN
	POP	DS
	RET	2

T2:
	CLI				; NO TIMER INTERRUPTS WHILE READING
	MOV	AL,TIMER_OFL
	MOV	TIMER_OFL,0		; GET OVERFLOW, AND RESET THE FLAG
	MOV	CX,TIMER_HIGH
	MOV	DX,TIMER_LOW
	JMP	T1			; TOD_RETURN

T3:
	CLI				; NO INTERRUPTS WHILE WRITING
	MOV	TIMER_LOW,DX
	MOV	TIMER_HIGH,CX		; SET THE TIME
	MOV	TIMER_OFL,0		; RESET OVERFLOW
	JMP	T1			; TOD_RETURN

RTC_0:
	DEC	AH			; AH=2
	JZ	RTC_2			; READ RTC TIME
	DEC	AH			; AH=3
	JZ	RTC_3			; SET RTC TIME
	JMP	RTC_1			; GO CHECK REMAINING FUNCTIONS
RTC_GET_TIME	PROC	NEAR

RTC_2:
	CALL	UPD_IN_IPR		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_2A			; GO AROUND IF OK
	JMP	T1_A			; RETURN IF ERROR
RTC_2A:
	CLI				; INTERRUPTS OFF DURING READ
	MOV	DL,-2
	CALL	PORT_INC_2		; SET ADDRESS OF SECONDS
	IN	AL,CMOS_PORT+1
	MOV	DH,AL			; SAVE
	CALL	PORT_INC_2		; SET ADDRESS OF MINUTES
	IN	AL,CMOS_PORT+1		;
	MOV	CL,AL			; SAVE
	CALL	PORT_INC_2		; SET ADDRESS OF HOURS
	IN	AL,CMOS_PORT+1		;
	MOV	CH,AL			; SAVE
	MOV	DL,0			; SET DL TO ZERO
	JMP	T1			; RETURN
RTC_GET_TIME	ENDP
;
RTC_SET_TIME	PROC	NEAR
RTC_3:
	CALL	UPD_IN_IPR		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_3A			; GO AROUND IF CLOCK OPERATING
	CALL	INITIALIZE_STATUS
RTC_3A:
	CLI				; INTERRUPTS OFF DURING SET
	PUSH	DX			; SAVE
	MOV	DL,-2			; FIRST ADDRESS
	CALL	PORT_INC_2		; UPDATE ADDRESS
	MOV	AL,DH			; GET TIME BYTE - SECONDS
	OUT	CMOS_PORT+1,AL		; STORE TIME BYTE
	CALL	PORT_INC_2		; UPDATE ADDRESS
	MOV	AL,CL			; GET TIME BYTE - MINUTES
	OUT	CMOS_PORT+1,AL		; STORE TIME BYTE
	CALL	PORT_INC_2		; UPDATE ADDRESS
	MOV	AL,CH			; GET TIME BYTE - HOURS
	OUT	CMOS_PORT+1,AL		; STORE TIME BYTE
	MOV	DL,0AH
	CALL	PORT_INC
	POP	DX			; RESTORE
	IN	AL,CMOS_PORT+1		; GET CURRENT VALUE
	AND	AL,23H			; MASK FOR VALID BIT POSITIONS
	OR	AL,DL			; GET DST BITHOUR MODE
	OR	AL,02H			; TURN ON 24 HOUR MODE
	PUSH	AX			;
	MOV	DL,0AH			;
	CALL	PORT_INC		;
	POP	AX			;
	OUT	CMOS_PORT+1,AL		;
	JMP	T1			; DONE
RTC_SET_TIME	ENDP

RTC_GET_DATE	PROC	NEAR
RTC_4:
	CALL	UPD_IN_IPR
	JNC	RTC_4A
	JMP	T1_A			; RETURN IF ERROR
RTC_4A:
	CLI				; INTERRUPTS OFF DURING READ
	MOV	DL,6
	CALL	PORT_INC		; POINT TO DAY
	IN	AL,CMOS_PORT+1
	MOV	CH,AL			; SAVE
	CALL	PORT_INC		; POINT TO MONTH
	IN	AL,CMOS_PORT+1
	MOV	DH,AL			; SAVE
	CALL	PORT_INC		; POINT TO YEAR
	IN	AL,CMOS_PORT+1
	MOV	CL,AL			; SAVE
	MOV	DL,31H			; POINT TO CENTURY BYTE SAVE AREA
	CALL	PORT_INC		;
	IN	AL,CMOS_PORT+1		; GET VALUE
	MOV	DL,CH			; GET DAY BACK
	MOV	CH,AL			;
	JMP	T1			; FINISHED
RTC_GET_DATE	ENDP
RTC_1:
	DEC	AH			; AH=4
	JZ	RTC_4			; READ RTC DATE
	DEC	AH			; AH=5
	JZ	RTC_5			; SET RTC DATE
	DEC	AH			; AH=6
	JZ	RTC_6			; SET RTC ALARM
	JMP	RTC_7			; RESET RTC ALARM

RTC_SET_DATE	PROC	NEAR
RTC_5:
	CALL	UPD_IN_IPR		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_5A			; GO AROUND IF CLOCK OPERATING
	CALL	INITIALIZE_STATUS
RTC_5A:
	CLI				; INTERRUPTS OFF DURING SET
	PUSH	CX			; SAVE
	MOV	CH,DL			; SAVE DAY OF MONTH
	MOV	DL,5			; ADDRESS DAY OF WEEK REGISTER
	CALL	PORT_INC
	MOV	AL,00H
	OUT	CMOS_PORT+1,AL		; LOAD ZEROS TO 'DAY OF WEEK' BYTE
	CALL	PORT_INC		; ADDRESS DAY OF MONTH REGISTER
	MOV	AL,CH			; GET DAY OF MONTH BYTE
	OUT	CMOS_PORT+1,AL		; STORE IT
	CALL	PORT_INC		; ADDRESS MONTH REGISTER
	MOV	AL,DH			; GET MONTH BYTE
	OUT	CMOS_PORT+1,AL		; STORE IT
	CALL	PORT_INC		; ADDRESS YEAR REGISTER
	MOV	AL,CL			; GET YEAR BYTE
	OUT	CMOS_PORT+1,AL		; STORE IT
	MOV	DL,0AH
	CALL	PORT_INC
	IN	AL,CMOS_PORT+1		; GET CURRENT SETTING
	AND	AL,07FH 		; CLEAR 'SET BIT'
	OUT	CMOS_PORT+1,AL		; *AND START CLOCK UPDATING
	POP	CX			; GET BACK
	MOV	DL,31H			; POINT TO SAVE AREA
	CALL	PORT_INC		;
	MOV	AL,CH			; GET CENTURY BYTE
	OUT	CMOS_PORT+1,AL		; SAVE IT
	JMP	T1			; FINISHED
RTC_SET_DATE	ENDP

RTC_SET_ALARM	PROC	NEAR
RTC_6:
	MOV	DL,0AH			; CHECK FOR ALARM ALREADY ENABLED
	CALL	PORT_INC		;
	IN	AL,CMOS_PORT+1		; GET CURRENT SETTING OF ALARM ENABLE
	TEST	AL,20H			;
	JZ	RTC_6A			; ALARM NOT SET - GO PROCESS
	XOR	AX,AX			;
	JMP	T1_A			; RETURN IF ERROR
RTC_6A:
	CALL	UPD_IN_IPR		; CHECK FOR UPDATE IN PROCESS
	JNC	RTC_6B
	CALL	INITIALIZE_STATUS
RTC_6B:
	CLI				; INTERRUPTS OFF DURING SET
	MOV	DL,-1
	CALL	PORT_INC_2
	MOV	AL,DH			; GET SECONDS BYTE
	OUT	CMOS_PORT+1,AL		; LOAD ALARM BYTE - SECONDS
	CALL	PORT_INC_2
	MOV	AL,CL			; GET MINUTES PARAMETER
	OUT	CMOS_PORT+1,AL		; LOAD ALARM BYTE - MINUTES
	CALL	PORT_INC_2
	MOV	AL,CH			; GET HOURS PARAMETER
	OUT	CMOS_PORT+1,AL		; LOAD ALARM BYTE - HOURS
	IN	AL,0A1H 		;ENSURE INTERRUPT UNMASKED
	AND	AL,0FEH 		;
	OUT	0A1H,AL 		;
	MOV	DL,0AH
	CALL	PORT_INC
	IN	AL,CMOS_PORT+1		; GET CURRENT VALUE
	AND	AL,07FH 		; ENSURE SET BIT TURNED OFF
	OR	AL,20H			; TURN ON ALARM ENABLE
	PUSH	AX			;
	MOV	DL,0AH			;
	CALL	PORT_INC		;
	POP	AX			;
	OUT	CMOS_PORT+1,AL		; ENABLE ALARM
	JMP	T1
RTC_SET_ALARM	ENDP

RTC_RESET_ALARM PROC	NEAR
RTC_7:
	CLI				; INTERRUPTS MASKED DURING RESET
	MOV	DL,0AH
	CALL	PORT_INC
	IN	AL,CMOS_PORT+1		; GET STATUS BYTE
	AND	AL,57H			; TURN OFF ALARM ENABLE
	PUSH	AX			; SAVE
	MOV	DL,0AH			;
	CALL	PORT_INC		;
	POP	AX			;
	OUT	CMOS_PORT+1,AL		; RESTORE
	JMP	T1
RTC_RESET_ALARM ENDP

RTC_TIMEBIOS_SUBR	PROC	NEAR
PORT_INC:
	INC	DL			; INCREMENT ADDRESS
	MOV	AL,DL
	OUT	CMOS_PORT,AL
	RET
;
PORT_INC_2:
	ADD	DL,2			; INCREMENT ADDRESS
	MOV	AL,DL
	OUT	CMOS_PORT,AL
	RET
;
INITIALIZE_STATUS	PROC	NEAR
;
	PUSH	DX			; SAVE
	MOV	DL,09H
	CALL	PORT_INC
	MOV	AL,26H
	OUT	CMOS_PORT+1,AL		; INITIALIZE 'A' REGISTER
	CALL	PORT_INC
	MOV	AL,82H			; SET 'SET BIT' FOR CLOCK INITIALIZATION
					; AND 24 HOUR MODE
	OUT	CMOS_PORT+1,AL		; INITIALIZE 'B' REGISTER
	CALL	PORT_INC
	IN	AL,CMOS_PORT+1		; READ REGISTER 'C' TO INITIALIZE
	CALL	PORT_INC
	IN	AL,CMOS_PORT+1		; READ REGISTER 'D' TO INITIALIZE
	POP	DX			; RESTORE
	RET
;
INITIALIZE_STATUS	ENDP
;
UPD_IN_IPR:
	PUSH	CX
	MOV	CX,600			; SET LOOP COUNT
UPDATE:
	MOV	AL,0AH			; ADDRESS OF 'A' REGISTER
	OUT	CMOS_PORT,AL
	JMP	$+2			; I/O TIME DELAY
	IN	AL,CMOS_PORT+1		; READ IN REGISTER 'A'
	TEST	AL,80H			; IF 8XH--> UIP BIT IS ON (CANNOT READ TIME)
	JZ	UPD_IN_PREND
	LOOP	UPDATE
	XOR	AX,AX			;
	STC				; SET CARRY FOR ERROR
UPD_IN_PREND:
	POP	CX
	RET				; RETURN WITH CY FLAG SET
;
RTC_TIMEBIOS_SUBR	ENDP
TIME_OF_DAY_1	ENDP
PAGE
;--INT 50 (LEVEL 8)----------------------------------------------
; THIS ROUTINE HANDLES THE PERIODIC AND ALARM INTERRUPTS FROM	:
; THE NON-VOLATILE TIMER.  INPUT FREQUENCY IS 1.024 KHZ 	:
; OR APPROXIMATELY 1024 INTERRUPTS EVERY SECOND FOR THE 	:
; PERIODIC INTERRUPT.  FOR THE ALARM FUNCTION, AN INTERRUPT WILL:
; OCCUR AT THE DESIGNATED TIME. 				:
;								:
; THE INTERRUPT IS ENABLED ONLY WHEN EVENT OR ALARM FUNCTIONS	:
; ARE ACTIVE.							:
; FOR THE EVENT INTERRUPT, THE HANDLER WILL DECREMENT THE	:
; WAIT COUNTER AND WHEN IT EXPIRES WILL TURN ON THE HIGH ORDER	:
; BIT OF THE DESIGNATED FLAG.					:
; FOR THE ALARM INTERRUPT, THE USER ROUTINE WILL BE INVOKED	:
; THROUGH INT 4AH.  THE USER MUST CODE A ROUTINE AND PLACE THE	:
; CORRECT ADDRESS IN THE VECTOR TABLE.				:
;----------------------------------------------------------------
RTC_INT PROC	FAR
	STI			; INTERRUPTS BACK ON
	PUSH	DS		; SAVE REGISTERS
	PUSH	AX		;
	PUSH	DX		;
	PUSH	DI		;
	MOV	DL,0AH		; GET ENABLES
	CALL	PORT_INC	;
	IN	AL,CMOS_PORT+1	;
	MOV	AH,AL		; SAVE
	CALL	PORT_INC	; GET SOURCE
	IN	AL,CMOS_PORT+1	;
	AND	AL,AH		;
	PUSH	AX		; SAVE
	TEST	AL,40H		; CHECK FOR PERIODIC INTERRUPT
	JZ	RTC_INT_9	; NO - GO AROUND
	CALL	DDS		; ESTABLISH ADDRESSABILITY
	SUB	RTC_LOW,0976	; DECREMENT COUNT
	SBB	RTC_HIGH,0	;
	JA	RTC_INT_9	;
	MOV	DL,0AH		; TURN OFF PIE
	CALL	PORT_INC	;
	IN	AL,CMOS_PORT+1	;
	AND	AL,0BFH 	;
	PUSH	AX		;
	MOV	DL,0AH		;
	CALL	PORT_INC	;
	POP	AX		;
	OUT	CMOS_PORT+1,AL	;
	MOV	RTC_WAIT_FLAG,0 ; SET FUNCTION ACTIVE FLAG OFF
	LDS	DI,DWORD PTR USER_FLAG ; SET UP DS:DI TO POINT TO USER FLAG
	MOV	BYTE PTR[DI],80H ; TURN ON USERS FLAG

RTC_INT_9:
	POP	AX		; GET INTERRUPT SOURCE BACK
	TEST	AL,20H		; TEST FOR ALARM INTERRUPT
	JZ	RTC_INT_10	; NO - GO AROUND
	INT	4AH		; TRANSFER TO USER ROUTINE
RTC_INT_10:
	MOV	AL,EOI		; END OF INTERRUPT TO 8259 - 2
	OUT	0A0H,AL
	OUT	020H,AL 	; AND TO 8259 - 1
	POP	DI		; RESTORE REGISTERS
	POP	DX		;
	POP	AX		;
	POP	DS		;
	IRET			; END OF INTERRUPT
RTC_INT ENDP
PAGE
;-- INT 8 (LEVEL 0)----------------------------------------------
; THIS ROUTINE HANDLES THE TIMER INTERRUPT FROM 		:
; CHANNEL 0 OF THE 8253 TIMER.	INPUT FREQUENCY IS 1.19318 MHZ	:
; AND THE DIVISOR IS 65536, RESULTING IN APPROX. 18.2 INTERRUPTS:
; EVERY SECOND. 						:
;								:
; THE INTERRUPT HANDLER MAINTAINS A COUNT OF INTERRUPTS SINCE	:
; POWER ON TIME, WHICH MAY BE USED TO ESTABLISH TIME OF DAY.	:
; THE INTERRUPT HANDLER ALSO DECREMENTS THE MOTOR CONTROL COUNT :
; OF THE DISKETTE, AND WHEN IT EXPIRES, WILL TURN OFF THE	:
; DISKETTE MOTOR(s), AND RESET THE MOTOR RUNNING FLAGS. 	:
; THE INTERRUPT HANDLER WILL ALSO INVOKE A USER ROUTINE THROUGH :
; INTERRUPT 1CH AT EVERY TIME TICK.  THE USER MUST CODE A	:
; ROUTINE AND PLACE THE CORRECT ADDRESS IN THE VECTOR TABLE.	:
;----------------------------------------------------------------

TIMER_INT_1	PROC  FAR      ;
	STI			; INTERRUPTS BACK ON
	PUSH	DS
	PUSH	AX
	PUSH	DX		; SAVE MACHINE STATE
	CALL	DDS		; ESTABLISH ADDRESSABILITY
	INC	TIMER_LOW	; INCREMENT TIME
	JNZ	T4		; GO TO TEST_DAY
	INC	TIMER_HIGH	; INCREMENT HIGH WORD OF TIME
T4:				; TEST_DAY
	CMP	TIMER_HIGH,018H ; TEST FOR COUNT EQUALLING 24 HOURS
	JNZ	T5		; DISKETTE_CTL
	CMP	TIMER_LOW,0B0H
	JNZ	T5		; DISKETTE_CTL

;------ TIMER HAS GONE 24 HOURS

	SUB	AX,AX
	MOV	TIMER_HIGH,AX
	MOV	TIMER_LOW,AX
	MOV	TIMER_OFL,1

;------ TEST FOR DISKETTE TIME OUT

T5:				; DISKETTE_CTL
	DEC	MOTOR_COUNT
	JNZ	T6		; RETURN IF COUNT NOT OUT
	AND	MOTOR_STATUS,0F0H	; TURN OFF MOTOR RUNNING BITS
	MOV	AL,0CH
	MOV	DX,03F2H		; FDC CTL PORT
	OUT	DX,AL		; TURN OFF THE MOTOR

T6:				; TIMER_RET
	INT	1CH		; TRANSFER CONTROL TO A USER ROUTINE
	MOV	AL,EOI
	OUT	020H,AL 	; END OF INTERRUPT TO 8259
	POP	DX
	POP	AX
	POP	DS		; RESET MACHINE STATE
	IRET			; RETURN FROM INTERRUPT
TIMER_INT_1	ENDP


;-- INT 5 --------------------------------------------------------------
;	THIS LOGIC WILL BE INVOKED BY INTERRUPT 05H TO PRINT
;	THE SCREEN. THE CURSOR POSITION AT THE TIME THIS ROUTINE
;	IS INVOKED WILL BE SAVED AND RESTORED UPON COMPLETION. THE
;	ROUTINE IS INTENDED TO RUN WITH INTERRUPTS ENABLED.
;	IF A SUBSEQUENT 'PRINT SCREEN KEY IS DEPRESSED DURING THE
;	TIME THIS ROUTINE IS PRINTING IT WILL BE IGNORED.
;	ADDRESS 50:0 CONTAINS THE STATUS OF THE PRINT SCREEN:
;
;	50:0	= 0	EITHER PRINT SCREEN HAS NOT BEEN CALLED
;			OR UPON RETURN FROM A CALL THIS INDICATES
;			A SUCCESSFUL OPERATION.
;
;		= 1	PRINT SCREEN IS IN PROGRESS
;
;		= 255	ERROR ENCOUNTERED DURING PRINTING
;-----------------------------------------------------------
	ASSUME	CS:CODE,DS:XXDATA



PRINT_SCREEN_1	PROC  FAR      ;
	STI			; MUST RUN WITH INTERRUPTS ENABLED
	PUSH	DS		; MUST USE 50:0 FOR DATA AREA STORAGE
	PUSH	AX
	PUSH	BX
	PUSH	CX		; WILL USE THIS LATER FOR CURSOR LIMITS
	PUSH	DX		; WILL HOLD CURRENT CURSOR POSITION
	MOV	AX,XXDATA	; HEX 50
	MOV	DS,AX
	CMP	STATUS_BYTE,1	; SEE IF PRINT ALREADY IN PROGRESS
	JZ	EXIT		; JUMP IF PRINT ALREADY IN PROGRESS
	MOV	STATUS_BYTE,1	; INDICATE PRINT NOW IN PROGRESS
	MOV	AH,15		; WILL REQUEST THE CURRENT SCREEN MODE
	INT	10H		;	[AL]=MODE
				;	[AH]=NUMBER COLUMNS/LINE
				;	[BH]=VISUAL PAGE
	; **********************************************************
	;	AT THIS POINT WE KNOW THE COLUMNS/LINE ARE IN
	;	[AX] AND THE PAGE IF APPLICABLE IS IN [BH]. THE STACK
	;	HAS DS,AX,BX,CX,DX PUSHED. [AL] HAS VIDEO MODE
	; **********************************************************
	MOV	CL,AH		; WILL MAKE USE OF [CX] REGISTER TO
	MOV	CH,25		; CONTROL ROW & COLUMNS
	CALL	CRLF		; CARRIAGE RETURN LINE FEED ROUTINE
	PUSH	CX		; SAVE SCREEN BOUNDS
	MOV	AH,3		; WILL NOW READ THE CURSOR.
	INT	10H		; AND PRESERVE THE POSITION
	POP	CX		; RECALL SCREEN BOUNDS
	PUSH	DX		; RECALL [BH]=VISUAL PAGE
	XOR	DX,DX		; WILL SET CURSOR POSITION TO [0,0]
; ***************************************************************
;	THE LOOP FROM PRR10 TO THE INSTRUCTION PRIOR TO PRI20
;	IS THE LOOP TO READ EACH CURSOR POSITION FROM THE SCREEN
;	AND PRINT.
; ***************************************************************
PRI10:
	MOV	AH,2		; TO INDICATE CURSOR SET REQUEST
	INT	10H		; NEW CURSOR POSITION ESTABLISHED
	MOV	AH,8		; TO INDICATE READ CHARACTER
	INT	10H		; CHARACTER NOW IN [AL]
	OR	AL,AL		; SEE IF VALID CHAR
	JNZ	PRI15		; JUMP IF VALID CHAR
	MOV	AL,' '          ; MAKE A BLANK
PRI15:
	PUSH	DX		; SAVE CURSOR POSITION
	XOR	DX,DX		; INDICATE PRINTER 1
	XOR	AH,AH		; TO INDICATE PRINT CHAR IN [AL]
	INT	17H		; PRINT THE CHARACTER
	POP	DX		; RECALL CURSOR POSITION
	TEST	AH, 29H 	; TEST FOR PRINTER ERROR
	JNZ	ERR10		; EXIT IF ERROR DETECTED
	INC	DL		; ADVANCE TO NEXT COLUMN
	CMP	CL,DL		; SEE IF AT END OF LINE
	JNZ	PRI10		; IF NOT PROCEED
	XOR	DL,DL		; BACK TO COLUMN 0
	MOV	AH,DL		; [AH]=0
	PUSH	DX		; SAVE NEW CURSOR POSITION
	CALL	CRLF		; LINE FEED CARRIAGE RETURN
	POP	DX		; RECALL CURSOR POSITION
	INC	DH		; ADVANCE TO NEXT LINE
	CMP	CH,DH		; FINISHED?
	JNZ	PRI10		; IF NOT CONTINUE
PRI20:	POP	DX		; RECALL CURSOR POSITION
	MOV	AH,2		; TO INDICATE CURSOR SET REQUEST
	INT	10H		; CURSOR POSITION RESTORED
	MOV	STATUS_BYTE,0	; INDICATE FINISHED
	JMP	SHORT EXIT	; EXIT THE ROUTINE
ERR10:	POP	DX		; GET CURSOR POSITION
	MOV	AH,2		; TO REQUEST CURSOR SET
	INT	10H		; CURSOR POSITION RESTORED
ERR20:	MOV	STATUS_BYTE,0FFH	; INDICATE ERROR

EXIT:	POP	DX		; RESTORE ALL THE REGISTERS USED
	POP	CX
	POP	BX
	POP	AX
	POP	DS
	IRET			; RETURN WITH INITIAL INTERRUPT MASK
PRINT_SCREEN_1	ENDP

;------ CARRIAGE RETURN, LINE FEED SUBROUTINE

CRLF	PROC	NEAR
	XOR	DX,DX		; PRINTER 0
	XOR	AH,AH		; WILL NOW SEND INITIAL LF,CR TO PRINTER
	MOV	AL,12Q		; LF
	INT	17H		; SEND THE LINE FEED
	XOR	AH,AH		; NOW FOR THE CR
	MOV	AL,15Q		; CR
	INT	17H		; SEND THE CARRIAGE RETURN
	RET
CRLF	ENDP
CODE	ENDS
	END
